package com.nevermore.shellexe

import android.content.ClipData
import android.content.Context
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.text.ClipboardManager
import android.text.SpannableString
import android.text.TextUtils
import android.text.style.ForegroundColorSpan
import android.util.Log
import android.view.inputmethod.InputMethodManager
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.nevermore.base.adapter.ArrayRVAdapter
import com.nevermore.shellexe.databinding.ActivityMainBinding
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.InputStream

class MainActivity : AppCompatActivity() {
    private lateinit var viewBinding: ActivityMainBinding

    private val inputMethodService by lazy {
        return@lazy ContextCompat.getSystemService(this, InputMethodManager::class.java)
    }

    private val TAG = "MainActivity"
    private var currentProcess: Process? = null


    private lateinit var mAdapter: ArrayRVAdapter<String>
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        viewBinding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(viewBinding.root)
        actionBar?.title  = "Pid-${android.os.Process.myPid()}"
        Log.i(TAG, "onCreate: ")
        initView()

    }

    private fun initView() {
        val clipboardManager =
            ContextCompat.getSystemService(this, android.content.ClipboardManager::class.java)

        viewBinding.apply {

            mAdapter = ArrayRVAdapter( contentProvider = {
                it
            } ){_,item: String ->

                val clipData = ClipData.newPlainText("cmd", item)
                clipboardManager?.setPrimaryClip(clipData)
                Toast.makeText(this@MainActivity, "复制成功:$item", Toast.LENGTH_SHORT).show()
            }
            rv.adapter = mAdapter
            mAdapter.addAll(listOf("/proc/cpuinfo"))

            val apm = APM()
            btnExecute.setOnClickListener {

                tvOutPut.text = ""
                val cmd = edtCmd.text.toString().trim()

                if (TextUtils.isEmpty(cmd)) {
                    Toast.makeText(this@MainActivity, "Please input cmd!", Toast.LENGTH_SHORT)
                        .show()
                    return@setOnClickListener
                }
                when {
                    cmd.startsWith("file") -> {
                        val filePath = cmd.substring(cmd.indexOf(":")+1)
                        val file = File(filePath)
                        displayFileContent(file)
                    }
                    else -> exec(cmd)
                }
                hideKeyboard()

            }


            btnStop.setOnClickListener {
                currentProcess?.destroy()
                tvOutPut.text = ""
                Log.i(TAG, "pid-${android.os.Process.myPid()} cpu usage :${apm.cpuUsage} %")
            }
        }
    }

    private fun displayFileContent(file: File) {
        lifecycleScope.launch (Dispatchers.IO){
            try {
                file.readLines().forEach {
                    displayInfo(it,false)
                }
            } catch (e: Exception) {
                displayInfo(e.message,true)
            }
        }
    }

    private fun hideKeyboard() {
        inputMethodService?.hideSoftInputFromWindow(viewBinding.edtCmd.windowToken, 0)
    }

    private fun exec(cmd: String) {
        lifecycleScope.launch {
            printCurrentThread("launch")
            try {
                val exec: Process = Runtime.getRuntime().exec(cmd)
                dumpInputStream(exec.inputStream, false)
                dumpInputStream(exec.errorStream, true)
                val waitFor = exec.waitFor()
                printCurrentThread("waitFor")
            } catch (e: Exception) {
                e.printStackTrace()
                displayInfo(e.message, true)
            }
        }
    }

    private fun printCurrentThread(tag: String) {
        Log.i(TAG, "$tag [${Thread.currentThread().name} - ${mainLooper == Looper.myLooper()}] ")
    }

    private suspend fun dumpInputStream(inputStream: InputStream, isError: Boolean) {
        withContext(Dispatchers.IO) {
            printCurrentThread("with io")
            inputStream.bufferedReader()
                .forEachLine { line ->
//                    runOnUiThread {
                    lifecycleScope.launch {
                        displayInfo(line, isError)
                    }
//                    }
                }
        }
    }

    private suspend fun displayInfo(line: String?, isError: Boolean) {
        line ?: return
        withContext(Dispatchers.Main) {
            with(SpannableString("$line\n")) sp@{
                setSpan(
                    ForegroundColorSpan(if (isError) Color.RED else Color.DKGRAY),
                    0,
                    this.length,
                    SpannableString.SPAN_INCLUSIVE_EXCLUSIVE
                )
                viewBinding.tvOutPut.append(this@sp)
            }
        }
    }
}